package expressions.slogo;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import parsing.Delay;
import parsing.Token;
import exceptions.UndefinedException;
import expressions.Expression;

/**
 * A user-defined command.
 * 
 */
@Token(regex = "[a-zA-z]+(\\?)?")
@Delay(order = 1)
public class UserCommand extends TurtleCommand
{
    public static class MethodSignature
    {
        public List<String> arguments;
        public Expression<Double> method;

        public MethodSignature(List<String> arguments, Expression<Double> method)
        {
            this.arguments = arguments;
            this.method = method;
        }
    }

    private static Map<String, MethodSignature> definedCommands = new TreeMap<String, MethodSignature>();

    private String name;

    public UserCommand(String cmdName)
    {
        super(0);

        if (definedCommands.containsKey(cmdName))
            arguments = definedCommands.get(cmdName).arguments.size();

        name = cmdName;
    }

    public static void defineCommand(String cmdName, MethodSignature cmd)
    {
        definedCommands.put(cmdName, cmd);
    }

    public String getName()
    {
        return name;
    }

    @Override
    protected Double combineResults(List<Double> results, ITurtleContext context)
    {
        if (definedCommands.containsKey(name))
        {
            MethodSignature cmd = definedCommands.get(name);

            for (int i = 0; i < arguments; i++)
            {
                context.setValue(cmd.arguments.get(i), results.get(i));
            }

            Double ans = cmd.method.evaluate(context);

            for (int i = 0; i < arguments; i++)
            {
                context.clearValue(cmd.arguments.get(i));
            }

            return ans;
        }
        else
            throw new UndefinedException(name);
    }
}
